package com.acme;

import java.io.IOException;
import java.util.List;

import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.domain.client.Client;
import com.acme.bankapp.exceptions.BankException;
import com.acme.bankapp.exceptions.NotEnoughFundsException;
import com.acme.bankapp.exceptions.OverDraftLimitExceededException;
import com.acme.bankapp.service.bank.BankDataLoaderService;
import com.acme.bankapp.service.bank.BankService;
import com.acme.bankapp.tcp.server.BankServer;

/**
 * Class used to manage bank, clients and accounts. Can print some useful
 * information.
 *
 * @author S.Zhidkov
 */

public class BankApplication {

    private static final String MESSAGE_BANK_CLIENTS = "Bank clients:";

    private static Bank bank;
    private static BankService bankService;
    private static BankDataLoaderService bankDataLoaderService;

    public BankApplication() {

    }

    private static void modifyBank() {
        List<Client> clients = bank.getClients();

        // change client 1
        clients.get(0).getAccounts().deposit(1000);
        try {
            clients.get(0).getAccounts().withdraw(1200);
        } catch (NotEnoughFundsException e) {
            e.printStackTrace();
        }

        // change client 2
        clients.get(1).getAccounts().deposit(150);
        try {
            clients.get(1).getAccounts().withdraw(300);
        } catch (OverDraftLimitExceededException e) {
            e.printStackTrace();
            System.out.println(e.getAccount().maximumAmountToWithdraw());
        } catch (NotEnoughFundsException e) {
            e.printStackTrace();
        }

    }

    /**
     * Prints balance of the all clients.
     */
    public static void printBalance() {
        List<Client> clients = bank.getClients();

        System.out.println();
        System.out.println(MESSAGE_BANK_CLIENTS);
        for (Client client : clients) {
            System.out.println(client);
        }
    }

    /**
     * Method starts bank server if used command line argument '-server'
     *
     * @param bank
     */
    public static void startServer(Bank bank) {
        BankServer bankServer = new BankServer(new CommandHandler(bank));
        try {
            bankServer.run();
        } catch (BankException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        // parse args
        // i use exec string:
        // "java com.acme.BankApplication -loadfeed ./files/feeds/clients.txt -loadbank ./files/serialized/bank.ser -server"
        ArgsHandler argsHandler = new ArgsHandler(args);

        // create services
        bankDataLoaderService = new BankDataLoaderService();
        bankService = new BankService();

        // read bank instance from file
        bank = bankService.readBank(argsHandler.getPathBankLoadFrom());

        // we are don't want add listeners in each deserialized instance and save it
        // bank.addListener(new Bank.PrintClientListener());
        // bank.addListener(new EmailNotificationListener());

        // read clients from feed file
        List<Client> clients = bankDataLoaderService.loadClients(argsHandler.getPathFeedFrom());

        // put clients into the bank
        bankService.addClients(bank, clients);

        if (argsHandler.isServer()) {
            startServer(bank);
        }

        // print balance on start
        printBalance();

        // modify some client accounts
        modifyBank();
        // save modified bank to the file
        bankService.saveBank(bank, argsHandler.getPathBankSaveTo());

        // again print changed balance
        printBalance();
        bankService.printMaximumAmountToWithdraw(bank);
    }

}